home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / POVSRC / SOURCE / CONES.C < prev    next >
Text File  |  1993-07-28  |  11KB  |  425 lines

  1. /****************************************************************************
  2. *                cones.c
  3. *
  4. *  This module implements the cone primitive.
  5. *  This file was written by Alexander Enzmann.    He wrote the code for
  6. *  cones and generously provided us these enhancements.
  7. *
  8. *  from Persistence of Vision Raytracer
  9. *  Copyright 1993 Persistence of Vision Team
  10. *---------------------------------------------------------------------------
  11. *  NOTICE: This source code file is provided so that users may experiment
  12. *  with enhancements to POV-Ray and to port the software to platforms other 
  13. *  than those supported by the POV-Ray Team.  There are strict rules under
  14. *  which you are permitted to use this file.  The rules are in the file
  15. *  named POVLEGAL.DOC which should be distributed with this file. If 
  16. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  17. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  18. *  Forum.  The latest version of POV-Ray may be found there as well.
  19. *
  20. * This program is based on the popular DKB raytracer version 2.12.
  21. * DKBTrace was originally written by David K. Buck.
  22. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  23. *
  24. *****************************************************************************/
  25.  
  26. #include "frame.h"
  27. #include "vector.h"
  28. #include "povproto.h"
  29.  
  30. METHODS Cone_Methods =
  31.   { 
  32.   All_Cone_Intersections,
  33.   Inside_Cone, Cone_Normal,
  34.   Copy_Cone, Translate_Cone, Rotate_Cone, Scale_Cone, Transform_Cone,
  35.   Invert_Cone, Destroy_Cone
  36.   };
  37.  
  38. extern long Ray_Cone_Tests, Ray_Cone_Tests_Succeeded;
  39. static int Intersect_Cone PARAMS((RAY *Ray, CONE *Cone, DBL *Depths));
  40.  
  41. #ifndef Cone_Tolerance
  42. #define Cone_Tolerance 1.0e-6
  43. #endif
  44.  
  45. #define close(x, y) (fabs(x-y) < EPSILON ? 1 : 0)
  46.  
  47. int All_Cone_Intersections (Object, Ray, Depth_Stack)
  48. OBJECT *Object;
  49. RAY *Ray;
  50. ISTACK *Depth_Stack;
  51.   {
  52.   DBL Depths[4];
  53.   VECTOR IPoint;
  54.   int Intersection_Found, cnt, i;
  55.  
  56.   Intersection_Found = FALSE;
  57.  
  58.   if ((cnt=Intersect_Cone (Ray, (CONE *)Object, Depths))!=0)
  59.     for (i=0; i<cnt; i++)
  60.     {
  61.     VScale (IPoint, Ray->Direction, Depths[i]);
  62.     VAddEq (IPoint, Ray->Initial);
  63.  
  64.     if (Point_In_Clip (&IPoint, Object->Clip))
  65.       {
  66.       push_entry(Depths[i],IPoint,Object,Depth_Stack);
  67.       Intersection_Found = TRUE;
  68.       }
  69.     }
  70.   return (Intersection_Found);
  71.   }
  72.  
  73. static int Intersect_Cone (Ray, Cone, Depths)
  74. RAY *Ray;
  75. CONE *Cone;
  76. DBL *Depths;
  77.   {
  78.   DBL a, b, c, z, t1, t2, len;
  79.   DBL d;
  80.   VECTOR P, D;
  81.   int i=0;
  82.  
  83.   Ray_Cone_Tests++;
  84.  
  85.   /* Transform the ray into the cones space */
  86.   MInvTransPoint(&P, &Ray->Initial, Cone->Trans);
  87.   MInvTransDirection(&D, &Ray->Direction, Cone->Trans);
  88.  
  89.   VLength(len, D);
  90.   VInverseScaleEq(D, len);
  91.  
  92.   if (Cone->cyl_flag) 
  93.     {
  94.     /* Solve intersections with a cylinder */
  95.     a = D.x * D.x + D.y * D.y;
  96.     if (a > EPSILON) 
  97.       {
  98.       b = P.x * D.x + P.y * D.y;
  99.       c = P.x * P.x + P.y * P.y - 1.0;
  100.       d = b * b - a * c;
  101.       if (d >= 0.0)
  102.         {
  103.         d = sqrt(d);
  104.         t1 = (-b + d) / a;
  105.         t2 = (-b - d) / a;
  106.         z = P.z + t1 * D.z;
  107.         if (t1 > Cone_Tolerance && t1 < Max_Distance && z >= 0.0 && z <= 1.0)
  108.           Depths[i++] = t1/len;
  109.         z = P.z + t2 * D.z;
  110.         if (t2 > Cone_Tolerance && t1 < Max_Distance && z >= 0.0 && z <= 1.0)
  111.           Depths[i++] = t2/len;
  112.         }
  113.       }
  114.     }
  115.   else
  116.     {
  117.     /* Solve intersections with a cone */
  118.     a = D.x * D.x + D.y * D.y - D.z * D.z;
  119.     b = D.x * P.x + D.y * P.y - D.z * P.z;
  120.     c = P.x * P.x + P.y * P.y - P.z * P.z;
  121.  
  122.     if (fabs(a) < EPSILON)
  123.       {
  124.       if (fabs(b) > EPSILON)
  125.         {
  126.         /* One intersection */
  127.         t1 = -0.5 * c / b;
  128.         z = P.z + t1 * D.z;
  129.         if (t1 > Cone_Tolerance && t1 < Max_Distance && z >= Cone->dist && z <= 1.0)
  130.           Depths[i++] = t1/len;
  131.         }
  132.       }
  133.     else
  134.       {
  135.       /* Check hits against the side of the cone */
  136.       d = b * b - a * c;
  137.       if (d >= 0.0)
  138.         {
  139.         d = sqrt(d);
  140.         t1 = (-b - d) / a;
  141.         t2 = (-b + d) / a;
  142.         z = P.z + t1 * D.z;
  143.         if (t1 > Cone_Tolerance && t1 < Max_Distance && z >= Cone->dist && z <= 1.0)
  144.           Depths[i++] = t1/len;
  145.         z = P.z + t2 * D.z;
  146.         if (t2 > Cone_Tolerance && t1 < Max_Distance && z >= Cone->dist && z <= 1.0)
  147.           Depths[i++] = t2/len;
  148.         }
  149.       }
  150.     }
  151.  
  152.   if (Cone->closed)
  153.     {
  154.     d = (1.0 - P.z) / D.z;
  155.     a = (P.x + d * D.x);
  156.     b = (P.y + d * D.y);
  157.     if ((a * a + b * b) <= 1.0 && d > Cone_Tolerance && d < Max_Distance)
  158.       Depths[i++] = d/len;
  159.     d = (Cone->dist - P.z) / D.z;
  160.     a = (P.x + d * D.x);
  161.     b = (P.y + d * D.y);
  162.     if ((a * a + b * b) <= (Cone->cyl_flag ? 1.0 : Cone->dist*Cone->dist)
  163.       && d > Cone_Tolerance && d < Max_Distance)
  164.       Depths[i++] = d/len;
  165.     }
  166.  
  167.   Ray_Cone_Tests_Succeeded +=i;
  168.  
  169.   return(i);
  170.   }
  171.  
  172. int Inside_Cone (IPoint, Object)
  173. VECTOR *IPoint;
  174. OBJECT *Object;
  175.   {
  176.   VECTOR New_Point;
  177.   CONE *Cone = (CONE *) Object;
  178.   DBL w2, z2, offset = (Cone->Inverted ? -EPSILON : EPSILON);
  179.  
  180.   /* Transform the point into the cones space */
  181.   MInvTransPoint(&New_Point, IPoint, Cone->Trans);
  182.  
  183.   /* Test to see if we are inside the cone */
  184.   w2 = New_Point.x * New_Point.x + New_Point.y * New_Point.y;
  185.   if (Cone->cyl_flag) 
  186.     {
  187.     /* Check to see if we are inside a cylinder */
  188.     if (w2 > 1.0 + offset ||
  189.       New_Point.z < 0.0 - offset ||
  190.       New_Point.z > 1.0 + offset)
  191.       return Cone->Inverted;
  192.     else
  193.       return 1 - Cone->Inverted;
  194.     }
  195.   else 
  196.     {
  197.     /* Check to see if we are inside a cone */
  198.     z2 = New_Point.z * New_Point.z;
  199.     if (w2 > z2 + offset ||
  200.       New_Point.z < Cone->dist - offset ||
  201.       New_Point.z > 1.0+offset)
  202.       return Cone->Inverted;
  203.     else
  204.       return 1 - Cone->Inverted;
  205.     }
  206.   }
  207.  
  208. void Cone_Normal (Result, Object, IPoint)
  209. OBJECT *Object;
  210. VECTOR *Result, *IPoint;
  211.   {
  212.   CONE *Cone = (CONE *) Object;
  213.  
  214.   /* Transform the point into the cones space */
  215.   MInvTransPoint(Result, IPoint, Cone->Trans);
  216.  
  217.   /* Calculating the normal is real simple in canonical cone space */
  218.   if (Result->z > (1-EPSILON))
  219.     Make_Vector(Result,0.0,0.0,1.0)
  220. else
  221.   if (Result->z < (Cone->dist+EPSILON))
  222.     Make_Vector(Result,0.0,0.0,-1.0)
  223. else
  224.   if (Cone->cyl_flag)
  225.     Result->z = 0.0;
  226.   else
  227.     Result->z = -Result->z;
  228.  
  229. /* Transform the point out of the cones space */
  230. MTransNormal(Result, Result, Cone->Trans);
  231. VNormalize(*Result, *Result);
  232. }
  233.  
  234. void *Copy_Cone (Object)
  235. OBJECT *Object;
  236. {
  237. CONE *New;
  238.  
  239. New  = Create_Cone();
  240. *New = *((CONE *) Object);
  241.  
  242. New->Trans = Copy_Transform(((CONE *)Object)->Trans);
  243.  
  244. return (New);
  245. }
  246.  
  247. void Translate_Cone (Object, Vector)
  248. OBJECT *Object;
  249. VECTOR *Vector;
  250. {
  251. TRANSFORM Trans;
  252.  
  253. Compute_Translation_Transform(&Trans, Vector);
  254. Transform_Cone(Object, &Trans);
  255. }
  256.  
  257. void Rotate_Cone (Object, Vector)
  258. OBJECT *Object;
  259. VECTOR *Vector;
  260. {
  261. TRANSFORM Trans;
  262. Compute_Rotation_Transform(&Trans, Vector);
  263. Transform_Cone(Object, &Trans);
  264. }
  265.  
  266. void Scale_Cone (Object, Vector)
  267. OBJECT *Object;
  268. VECTOR *Vector;
  269. {
  270. TRANSFORM Trans;
  271.  
  272. Compute_Scaling_Transform(&Trans, Vector);
  273. Transform_Cone(Object, &Trans);
  274. }
  275.  
  276. void Invert_Cone (Object)
  277. OBJECT *Object;
  278. {
  279. ((CONE *)Object)->Inverted = 1 - ((CONE *)Object)->Inverted;
  280. }
  281.  
  282. void Transform_Cone (Object, Trans)
  283. OBJECT *Object;
  284. TRANSFORM *Trans;
  285. {
  286. CONE *Cone = (CONE *)Object;
  287. Compose_Transforms(Cone->Trans, Trans);
  288.  
  289. /* Recalculate the bounds */
  290. Make_Vector(&Cone->Bounds.Lower_Left, -1.0, -1.0, 0.0);
  291. Make_Vector(&Cone->Bounds.Lengths, 2.0, 2.0, 1.0);
  292. recompute_bbox(&Cone->Bounds, Cone->Trans);
  293. }
  294.  
  295. CONE *Create_Cone ()
  296. {
  297. CONE *New;
  298.  
  299. if ((New = (CONE *) malloc (sizeof (CONE))) == NULL)
  300. MAError ("cone");
  301.  
  302. INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
  303. Make_Vector (&(New->apex), 0.0, 0.0, 1.0);
  304. Make_Vector (&(New->base), 0.0, 0.0, 0.0);
  305. New->apex_radius = 1.0;
  306. New->base_radius = 0.0;
  307. New->dist = 0.0;
  308. New->Trans = Create_Transform();
  309. New->Inverted = FALSE;
  310. New->cyl_flag = 0; /* This is a Cone */
  311. New->closed   = 1; /* Has capped ends*/
  312.  
  313. /* Default bounds */
  314. Make_Vector(&New->Bounds.Lower_Left, -1.0, -1.0, 0.0);
  315. Make_Vector(&New->Bounds.Lengths, 2.0, 2.0, 1.0);
  316.  
  317. return New;
  318. }
  319.  
  320. CONE *Create_Cylinder ()
  321. {
  322. CONE *New;
  323.  
  324. if ((New = (CONE *) malloc (sizeof (CONE))) == NULL)
  325. MAError ("cone");
  326.  
  327. INIT_OBJECT_FIELDS(New, CONE_OBJECT, &Cone_Methods)
  328. Make_Vector (&(New->apex), 0.0, 0.0, 1.0);
  329. Make_Vector (&(New->base), 0.0, 0.0, 0.0);
  330. New->apex_radius = 1.0;
  331. New->base_radius = 1.0;
  332. New->dist = 0.0;
  333. New->Trans = Create_Transform();
  334. New->Inverted = FALSE;
  335. New->cyl_flag = 1; /* This is a Cylinder */
  336. New->closed   = 1; /* Has capped ends*/
  337.  
  338. /* Default bounds */
  339. Make_Vector(&New->Bounds.Lower_Left, -1.0, -1.0, 0.0);
  340. Make_Vector(&New->Bounds.Lengths, 2.0, 2.0, 1.0);
  341.  
  342. return New;
  343. }
  344.  
  345. void Compute_Cone_Data(Object)
  346. OBJECT *Object;
  347. {
  348. DBL tlen, len, tmpf;
  349. VECTOR tmpv, axis, origin;
  350. CONE *Cone = (CONE *)Object;
  351.  
  352. /* Process the primitive specific information */
  353. if(Cone->apex_radius < Cone->base_radius) 
  354.   {
  355.   /* Want the bigger end at the top */
  356.   tmpv = Cone->base;
  357.   Cone->base = Cone->apex;
  358.   Cone->apex = tmpv;
  359.   tmpf = Cone->base_radius;
  360.   Cone->base_radius = Cone->apex_radius;
  361.   Cone->apex_radius = tmpf;
  362.   }
  363. else if (fabs(Cone->apex_radius - Cone->base_radius) < EPSILON) 
  364.   {
  365.   /* What we are dealing with here is really a cylinder */
  366.   Cone->cyl_flag = 1;
  367.   Compute_Cylinder_Data(Object);
  368.   return;
  369.   }
  370.  
  371. /* Find the axis and axis length */
  372. VSub(axis, Cone->apex, Cone->base);
  373. VLength(len, axis);
  374. if (len < EPSILON)
  375. Error("Degenerate cone/cylinder\n");
  376. else
  377.   VInverseScaleEq(axis, len)
  378.  
  379.     /* Determine alignment */
  380.     tmpf = Cone->base_radius *
  381.     len / (Cone->apex_radius - Cone->base_radius);
  382. VScale(origin, axis, tmpf);
  383. VSub(origin, Cone->base, origin);
  384. tlen = tmpf + len;
  385. Cone->dist = tmpf / tlen;
  386. Compute_Coordinate_Transform(Cone->Trans, &origin, &axis,
  387. Cone->apex_radius, tlen);
  388.  
  389. /* Recalculate the bounds */
  390. Make_Vector(&Cone->Bounds.Lower_Left, -1.0, -1.0, 0.0);
  391. Make_Vector(&Cone->Bounds.Lengths, 2.0, 2.0, 1.0);
  392. recompute_bbox(&Cone->Bounds, Cone->Trans);
  393. }
  394.  
  395. void Compute_Cylinder_Data(Object)
  396. OBJECT *Object;
  397. {
  398. CONE *Cone = (CONE *)Object;
  399. VECTOR axis;
  400. DBL tmpf;
  401.  
  402. VSub(axis, Cone->apex, Cone->base);
  403. VLength(tmpf, axis);
  404. if (tmpf < EPSILON)
  405. Error("Degenerate cylinder, base point = apex point\n");
  406. else
  407.   VInverseScaleEq(axis, tmpf)
  408.     Compute_Coordinate_Transform(Cone->Trans, &Cone->base, &axis,
  409.       Cone->apex_radius, tmpf);
  410.  
  411. Cone->dist = 0.0;
  412. /* Recalculate the bounds */
  413. Make_Vector(&Cone->Bounds.Lower_Left, -1.0, -1.0, 0.0);
  414. Make_Vector(&Cone->Bounds.Lengths, 2.0, 2.0, 1.0);
  415. recompute_bbox(&Cone->Bounds, Cone->Trans);
  416. }
  417.  
  418.  
  419. void Destroy_Cone (Object)
  420. OBJECT *Object;
  421. {
  422. Destroy_Transform(((CONE *)Object)->Trans);
  423. free (Object);
  424. }
  425.